using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;

namespace MoonRainbow.Input.Mouse
{
    internal class MouseEventHandlerCollection : Collection<MouseRightButtonEventHandler>
    {
        public MouseEventHandlerCollection(EventStrategy strategy, UIElement element, DependencyProperty eventProperty)
        {
            _strategy = strategy;
            _element = element;
            _eventProperty = eventProperty;
        }

        private readonly UIElement _element;

        private readonly EventStrategy _strategy;

        private readonly DependencyProperty _eventProperty;

        public EventStrategy Strategy { get { return _strategy; } }

        public bool InvokeHandlers(MouseRightButtonEventArgs e)
        {
            var args = new MouseRightButtonEventArgs(e.GetPosition(Application.Current.RootVisual),
                                                     e.OriginalSource ?? _element, _element);
            IList<MouseRightButtonEventHandler> list = new List<MouseRightButtonEventHandler>(this);
            foreach (var handler in list)
                handler(_element, args);
            e.IsHandled = args.IsHandled;
            if (e.IsHandled) return true;
            MouseEventHandlerCollection handlers;
            switch (Strategy)
            {
                #region Bubbling
                case EventStrategy.Bubbling:
                    var parent = (UIElement) VisualTreeHelper.GetParent(_element);
                    if (parent == null) break;
                    handlers = (MouseEventHandlerCollection)parent.GetValue(_eventProperty);
                    if (handlers==null)
                    {
                        handlers = new MouseEventHandlerCollection(Strategy, parent, _eventProperty);
                        parent.SetValue(_eventProperty, handlers);
                    }
                    e.IsHandled = handlers.InvokeHandlers(new MouseRightButtonEventArgs(
                                                e.GetPosition(Application.Current.RootVisual),
                                                e.OriginalSource ?? _element, parent));
                    break;
                #endregion

                #region Tunneling
                case EventStrategy.Tunneling:
                    IList<UIElement> elements =
                        new List<UIElement>(VisualTreeHelper.FindElementsInHostCoordinates(args.GetPosition(_element),
                                                                                           _element));
                    if (elements.Count == 0) break;
                    if (elements[0] == _element) break;
                    var curel = elements[0];
                    while (VisualTreeHelper.GetParent(curel)!=_element)
                        curel = (UIElement)VisualTreeHelper.GetParent(curel);
                    handlers = (MouseEventHandlerCollection) curel.GetValue(_eventProperty);
                    if (handlers == null)
                    {
                        handlers = new MouseEventHandlerCollection(Strategy, curel, _eventProperty);
                        curel.SetValue(_eventProperty, handlers);
                    }
                    e.IsHandled = handlers.InvokeHandlers(new MouseRightButtonEventArgs(
                                                e.GetPosition(Application.Current.RootVisual),
                                                e.OriginalSource ?? _element, curel));
                    break;
                #endregion
            }
            return e.IsHandled;
        }
    }
}